// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: gekim

#include <filesystem>
#include <memory>

#include <cxxopts.hpp>

#include "appcoin2/support/feed/fastfeed_util.h"
#include "coin2/app/driver.h"
#include "coin2/base/config/app_config.h"
#include "coin2/base/config/args.h"
#include "coin2/exchange/base/executor/sync_executor.h"
#include "coin2/exchange/base/market/market_exchange_api.h"
#include "coin2/feed/universe/writer.h"
#include "coin2/strategy/strategy.h"

// proto
#include "coin2/exchange/feed.pb.h"

using namespace coin2::base::config;
using namespace coin2::app;
using namespace coin2::exchange::base::symbology;
using namespace coin2::exchange::feed;
using coin2::exchange::base::feed::FeedUpdate;
using coin2::exchange::base::symbology::IProduct;
using coin2::exchange::di::ConstantInjectionBuilder;
using coin2::feed::fastfeed::FastFeedWriter;
using coin2::feed::fastfeed::FastFeedUniverseWriter;
using ::fastfeed::proto::BookBuilderParameter;

// class FastFeedUniverseSubConverter : public FastFeedSubConverter {
//  public:
//   FastFeedUniverseSubConverter(
//       const std::string& recipe,
//       const std::string& out_dir,
//       const std::string& dest_proto_tag)
//       : FastFeedSubConverter(recipe, out_dir), dest_proto_tag_(dest_proto_tag) {}

//   void Init(::coin2::app::Driver* driver) override {
//     // Converter only support single mea execution.

//     const auto& config = driver->config().feed();
//     int worker = config.common().archive().worker();
//     auto it = config.exchanges().begin();
//     auto& exchange_config = it->second;
//     auto& archive_config = exchange_config.archive();

//     int worker_id = 0;
//     if (!archive_config.shift() && !archive_config.arbitration()) {
//       worker_id = archive_config.worker();
//       CHECK_EQ_THROW(worker, worker_id) << "fastfeed converter supports only one worker in one run";
//     }

//     auto mea = MarketExchangeApi::FromString(exchange_config.mea());
//     LOG(INFO) << "FastFeedUniverseWriter:" << config.common().archive().interval().start();
//     writer_ = std::make_unique<FastFeedUniverseWriter>(
//         out_dir_,
//         archive_config.machine(),
//         mea,
//         recipe_,
//         worker_id,
//         ".lz4",
//         config.common().archive().interval().start(),
//         dest_proto_tag_);

//     // Warmup period should be handled by parser but ignored by strategy.
//     auto interval = FromIntervalConfig(archive_config.interval());
//     start_from_ = interval.first;
//     proto_ = fastfeed::proto::Feed();
//     if (recipe_.find("light_bbo") != std::string::npos) {
//       publish_bbo_book_only_ = true;
//       publish_book_level_ = 5;
//     } else {
//       publish_bbo_book_only_ = exchange_config.raw_parser().publish_bbo_book_only();
//       publish_book_level_ = exchange_config.raw_parser().book_level();
//     }
//   }

//  private:
//   std::string dest_proto_tag_;
// };

// class FastFeedUniverseConverter : public FastFeedConverter {
//  public:
//   explicit FastFeedUniverseConverter(
//       const std::string& proto_feed_universe_root,
//       const std::string& dest_proto_tag)
//       : FastFeedConverter(proto_feed_universe_root),
//         proto_feed_universe_root_dir_(proto_feed_universe_root),
//         dest_proto_tag_(dest_proto_tag){}

//   void Init(::coin2::app::Driver* driver) override {
//     // Converter only support single mea execution.
//     const auto& config = driver->config().feed();
//     auto it = config.exchanges().begin();
//     auto& exchange_config = it->second;
//     auto recipe = exchange_config.recipe();
//     LOG(INFO) << recipe;
//     auto sub_converter =
//         std::make_unique<FastFeedUniverseSubConverter>(recipe, out_dir_, dest_proto_tag_);
//     sub_converter->Init(driver);
//     sub_converters_[recipe] = std::move(sub_converter);
//   }

//  private:
//   std::experimental::filesystem::path proto_feed_universe_root_dir_;
//   std::string dest_proto_tag_;
// };

class FastFeedUniverseConverter : public FastFeedSubConverter {
 public:
  FastFeedUniverseConverter(
      const std::string& proto_feed_universe_root,
      const std::string& dest_proto_tag)
      : FastFeedSubConverter("", proto_feed_universe_root), dest_proto_tag_(dest_proto_tag) {}

  void Init(::coin2::app::Driver* driver) override {
    // Converter only support single mea execution.

    const auto& config = driver->config().feed();
    auto it = config.exchanges().begin();
    auto& exchange_config = it->second;
    auto& archive_config = exchange_config.archive();
    recipe_ = exchange_config.recipe();

    auto mea = MarketExchangeApi::FromString(exchange_config.mea());
    LOG(INFO) << "FastFeedUniverseWriter:" << config.common().archive().interval().start();
    writer_ = std::make_unique<FastFeedUniverseWriter>(
        out_dir_,
        archive_config.machine(),
        mea,
        recipe_,
        0,
        ".lz4",
        config.common().archive().interval().start(),
        dest_proto_tag_);

    // Warmup period should be handled by parser but ignored by strategy.
    auto interval = FromIntervalConfig(archive_config.interval());
    start_from_ = interval.first;
    proto_ = fastfeed::proto::Feed();
    if (recipe_.find("light_bbo") != std::string::npos) {
      publish_bbo_book_only_ = true;
      publish_book_level_ = 5;
    } else {
      publish_bbo_book_only_ = exchange_config.raw_parser().publish_bbo_book_only();
      publish_book_level_ = exchange_config.raw_parser().book_level();
    }
  }

 private:
  std::string dest_proto_tag_;
};

int main(int argc, char* argv[]) {
  DriverConfig app;

  cxxopts::Options opt("FastFeed Replate", "Replay fastfeed to a new recipe");
  SetupOptions(&opt);
  opt.add_options()(
      "proto_feed_universe_root",
      "fastfeed universe out directory",
      cxxopts::value<std::string>()->default_value(
          "/remote/iosg/coin-2/buckets/feed.derived.feed_cache.coin2/universe"))(
      "dest_proto_tag",
      "fastfeed universe tag",
      cxxopts::value<std::string>()->default_value("l1.default.tag"))(
      "log-dir",
      "fastfeed log directory",
      cxxopts::value<std::string>()->default_value("/remote/iosg/jenkins-2/bot-coin/jenkins/workspace/coin2_fastfeed/logs"));

  auto res = opt.parse(argc, argv);

  ParseOptionsIntoConfig(res, &app);

  auto archive = app.mutable_feed()->mutable_common()->mutable_archive();
  archive->set_worker(0);

  spdlog::info("=== FastFeed Universe Converter start ===");
  LogAppConfig(res, app);
  spdlog::warn("running ..");

  FastFeedUniverseConverter converter(
      res["proto_feed_universe_root"].as<std::string>(),
      res["dest_proto_tag"].as<std::string>());

  ConstantInjectionBuilder ci_builder = ConstantInjectionBuilder();
  coin2::app::Driver driver(app, &converter, ci_builder);
  driver.Run();

  spdlog::info("=== FastFeed Universe Converter done ===");
  return 0;
}
